package com.gitee.wsl.collections.iterator

import com.gitee.wsl.ext.list.pop
import com.gitee.wsl.ext.list.push

/**
 * Decorates an iterator to support pushback of elements.
 *
 *
 * The decorator stores the pushed back elements in a LIFO manner: the last element
 * that has been pushed back, will be returned as the next element in a call to [.next].
 *
 *
 *
 * The decorator does not support the removal operation. Any call to [.remove] will
 * result in an [UnsupportedOperationException].
 *
 *
 * @param <E> the type of elements returned by this iterator.
 * @since 4.0
</E> */
class PushbackIterator<E>(
    /** The iterator being decorated.  */
    private val iterator: Iterator<E>,
) : Iterator<E> {
    /** The LIFO queue containing the pushed back items.  */
    private val items = ArrayDeque<E>()

    public override fun hasNext(): Boolean {
        return !items.isEmpty() || iterator.hasNext()
    }

    public override fun next(): E {
        return if (!items.isEmpty()) items.pop() else iterator.next()
    }

    /**
     * Push back the given element to the iterator.
     *
     *
     * Calling [.next] immediately afterwards will return exactly this element.
     *
     *
     * @param item  the element to push back to the iterator
     */
    fun pushback(item: E) {
        items.push(item)
    }

    /**
     * This iterator will always throw an [UnsupportedOperationException].
     *
     * @throws UnsupportedOperationException always
     */
//    public override fun remove() {
//        throw java.lang.UnsupportedOperationException()
//    }

    companion object {
        /**
         * Decorates the specified iterator to support one-element lookahead.
         *
         *
         * If the iterator is already a [PushbackIterator] it is returned directly.
         *
         *
         * @param <E>  the element type
         * @param iterator  the iterator to decorate
         * @return a new peeking iterator
         * @throws NullPointerException if the iterator is null
        </E> */
        fun <E> pushbackIterator(iterator: Iterator<E>): PushbackIterator<E> {
            if (iterator is PushbackIterator<*>) {
                val it = iterator as PushbackIterator<E>
                return it
            }
            return PushbackIterator(iterator)
        }
    }
}
